選択型を DTO に変換する
選択型は特殊なレコード型で表現する
使用されている選択肢を示す「タグ」
各可能なケースに関連するデータを含む「フィールド」
warning.icon シリアライザによっては 選択型 を直接扱えるものもあるが、フォーマットはコントロールできないことが多い 別のシリアライザを利用している、別の 境界づけられたコンテキスト が、その方法を知らない場合に問題となることがあるため、明示的にフォーマットをコントロールしたほうが良い e.g.
code:domain.fs
type Name =
{ First: String50
Last: String50 }
type Example =
| A
| B of int
| C of string list
| D of Name
code:dto.fs
type NameDto =
{ First: string
Last: string }
type ExampleDto =
{ Tag: string
BData: Nullable<int>
CData: string[]
DData: NameDto }
シリアライズパイプラインの実装
code:dto.fs
let nameDtoFromDomain (name: Domain.Name): NameDto =
let first = name.First |> String50.value
let last = name.Last |> String50.value
{ First = first; Last = last }
let fromDomain (domainObj: Domain.Example): ExampleDto =
let nullBData = Nullable()
let nullCData = null
let nullDData = Unchecked.defaultof<NameDto>
match domainObj with
| A ->
{ Tag = "A"; BData = nullBData; CData = nullCData; DData = nullDData }
| B i ->
let bdata = Nullable i
{ Tag = "B"; BData = bdata; CData = nullCData; DData = nullDData }
| C strList ->
let cdata = strList |> List.toArray
{ Tag = "C"; BData = nullBData; CData = cdata; DData = nullDData }
| D name ->
let ddata = name |> nameDtoFromDomain
{ Tag = "D"; BData = nullBData; CData = nullCData; DData = ddata }
B: Nullable<_> に null を直接割り当てられないので、Nullable 関数(コンストラクタ)を用いる
C: Array は .NET のクラスなので、null を代入可能
D: NameDto のようなレコードも null を割り当てられないので、Unchecked.defaultof<_> を用いて null 値を作成している
デシリアライズパイプラインの実装
「タグ」フィールドでマッチさせ、それぞれのケースを処理する
このとき、タグに関連付けられたデータが null でないことを必ずチェックする
code:dto.fs
let nameDtoToDomain (nameDto: NameDto): Result<Domain.Name,string> =
result {
let! first = nameDto.First |> String50.create
let! last = nameDto.Last |> String50.create
return { First = first; Last = last }
}
let toDomain dto: Result<Domain.Example,string> =
match dto.Tag with
| "A" -> Ok A
| "B" ->
if dto.BData.HasValue then
dto.BData.Value |> B |> Ok
else
Error "B data not expected to be null"
| "C" ->
match dto.CData with
| null -> Error "C data not expected to be null"
| _ -> dto.CData |> Array.toList |> C |> Ok
| "D" ->
match box dto.DData with
| null -> Error "D data not expected to be null"
| _ ->
dto.DData
|> nameDtoToDomain // Result<Domain.Name,string>
|> Result.map D // Result<Example.D,string>
| _ ->
let msg = sprintf "Tag '%s' not recognized" dto.Tag
Error msg
box ?? radish-miyazaki.icon obj 型(System.Object)に変換することで、null でパターンマッチできるようにしてるっぽい